/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  TableCodec_Decode.cpp
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2019/09/11
  *Desc		:  解码
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#include "TableCodec.h"
//#include "common_util.h"
#include "StopCodec.h"
#include "FieldCollector.h"
#include "BitView.h"
#include "../zstd.h"
#include <cstdio>
#include <cstdlib>
#include <algorithm>
namespace qb{
	namespace proto{

		// 将op操作符从二进制解码成整数数组
		bool GetOpArray(int count, const VarValue& opsValue, OpBitmap& fieldOps)
		{
			// 每2bit为一个字段对应的op值
			if (count * OpBitWidth > opsValue.str.len*CHAR_BIT)
				return false;
			fieldOps.clear();
			fieldOps.reserve(count);
			BitView view((const unsigned char*)opsValue.str.ptr, opsValue.str.len, 2, false,false);
			BASSERT(view.size() >= count);
			for (int i = 0; i < count; i++)
				fieldOps[i]=view.at(i);
			BASSERT(fieldOps.size() == count);
			return true;
		}

		class CollectorSortByKey{
		public:
			CollectorSortByKey(){}
			bool operator()(const FieldCollectorPtr& c1, const FieldCollectorPtr& c2)const
			{
				return c1->GetKey() < c2->GetKey();
			}
		};


		void TableCodec::FixConvertValue(VarValue& fieldValue, kEncodeType type)
		{
			/*
				只存在2种转化
				kExpectTypeString ==> kEncodeTypeVarInt
				kExpectTypeDouble ==> kEncodeTypeStrNum
			*/
			BASSERT(type == kEncodeTypeVarInt || type == kEncodeTypeStrNum||
				type==kEncodeTypeDouble);
			if (type == kEncodeTypeVarInt)
			{
				/*if (fieldValue.IsDefault())
					fieldValue = VarValue((const char*)NULL, 0);
				else*/
				{
					char buf[64] = { 0 };
#ifndef WIN32
                    int len = _snprintf_s(buf, 64, "%lld", fieldValue.i);
#else
					int len = _snprintf_s(buf, 64, "%I64d", fieldValue.i);

#endif
					fieldValue = VarValue(AllocString(buf, len), len);
				}
			}
			else if (type == kEncodeTypeStrNum)
			{
				if (fieldValue.IsDefault())
					fieldValue = VarValue(0.0);
				else
					fieldValue = VarValue(atof(fieldValue.str.ptr));
			}
		}
		VarValue GetDefaultValue(kEncodeType type)
		{
			switch (type)
			{
			case kEncodeTypeStrRaw:
			case kEncodeTypeStrAlpNum:
			case kEncodeTypeStrNum:return VarValue((const char*)NULL, 0);
			case kEncodeTypeVarInt:
			case kEncodeTypeVarUint:return VarValue(0);
			case kEncodeTypeDouble:return VarValue(0.0);
				break;
			}
			return VarValue();
		}
		FieldCollectorPtr TableCodec::DecodeColumn(StopCodec& decoder, int ncount, int colIndex)
		{
			// type,opbitmap?,dictid?,bitwidth?,v0,v1,v2,v3,...
			int row = ncount;
			unsigned char flag = (unsigned char)decoder.GetInt(0);
			kEncodeType type = (kEncodeType)(flag&EncodeTypeMask);
			kEncodeType dftType = type;
			BASSERT(type < kEncodeTypeAuto);
			OpBitmap fieldOps;
			bool hasOpBitmap = flag&FieldFlagHasOpBitmap;
			bool hasConvert = flag & FieldFlagHasConvert;
			if (hasOpBitmap)
			{
				VarValue opsValue;
				if (!decoder.GetValue(kEncodeTypeStrRaw, opsValue, this))
					return NULL;
				if (!GetOpArray(row, opsValue, fieldOps))
					return NULL;
				BASSERT(row == fieldOps.size());
			}

			VarValue fieldValue;
			FieldCollectorPtr collector = new FieldCollector(type, colIndex, row);
			if (hasOpBitmap)
				collector->SetOpBitmap(fieldOps);
			int dictIndex = -1;
			if (flag&FieldFlagHasDictIndex)
			{
				dictIndex = (int)decoder.GetInt(kEncodeTypeVarInt);
				collector->SetDictIndex(dictIndex);
			}

			if (type == kEncodeTypeFixedBit)
			{
				int bitWidth = (int)decoder.GetInt(kEncodeTypeVarInt);
				collector->SetBitWidth(bitWidth);
			}

			// 解码一列的所有数据
			bool useDict = dictIndex >= 0 && dictIndex < (int)m_dicts.size();
			for (int i = 0; i < row; i++)
			{
				unsigned int op = hasOpBitmap ? fieldOps[i] : kOpTypeNew;
				if (useDict)
				{
					BASSERT(op == kOpTypeNew);
				}
				switch (op)
				{
				case kOpTypeNew://读取,全新值
					decoder.GetValue(type, fieldValue, this);
					if (hasConvert)
					{
						FixConvertValue(fieldValue, type);
					}
					if (useDict)//使用字典的情况
					{
						BASSERT(type == kEncodeTypeVarInt);
						FieldCollectorPtr& dict = m_dicts[dictIndex];
						int index = (int)fieldValue.i;
						collector->AddValue(i, dict->GetValue(index));
					}
					else
						collector->AddValue(i, fieldValue);
					break;
				case kOpTypeDefault://忽略,不读取,直接使用默认值
					dftType = type;
					if (hasConvert)
					{
						/*
						只存在2种转化,参见FixConvertValue
						kExpectTypeString ==> kEncodeTypeVarInt
						kExpectTypeDouble ==> kEncodeTypeStrNum
						*/
						if (type == kEncodeTypeVarInt)
							dftType = kEncodeTypeStrRaw;
						else if (type == kEncodeTypeStrNum)
							dftType = kEncodeTypeDouble;
					}
					fieldValue = GetDefaultValue(dftType);
					collector->AddValue(i, fieldValue);
					break;
				case kOpTypeCopy://忽略,不读取,直接使用前一个值
					collector->AddValue(i, fieldValue);
					break;
				case kOpTypeDelta://读取,变化值
				{
					VarValue deltaValue;
					decoder.GetValue(type, deltaValue, this);
					if (hasConvert)
						FixConvertValue(deltaValue, type);
					fieldValue.AddDelta(deltaValue, this);
					collector->AddValue(i, fieldValue);
				}
				break;
				default:
					BASSERT(0);
					return NULL;
					break;
				}
			}
			return collector;
		}
		int TableCodec::Decode(unsigned char* buf, int size)
		{
			// 将解码后的数据放在FieldCollector中
			// 首先解码头部
			// 其次,解码字典数组,前期可忽略
			// 其次,解码第一列数据,第二列数据,第三列数据
			StopCodec decoder(buf, size,false);
			unsigned char flag = (unsigned char)decoder.GetInt(0);
			kEncodeType type = (kEncodeType)(flag&EncodeTypeMask);
			if (type != kEncodeTypeTable)
				return -1;

			if (flag & TableFlagHasZipped)
			{
				int nzip = (int)decoder.GetInt();	// 压缩大小
				int nsize = (int)decoder.GetInt();	// 原始大小
				PrepareBuffer(nsize);
				size_t nzip2 = ZSTD_decompress(m_zbuf, m_zbuf_size, buf + decoder.GetPos(), nzip);
				if (nsize != nsize || ZSTD_isError(nzip2))
					return -1;
				decoder.Init((unsigned char*)m_zbuf, nsize,false);
				size = nsize;
			}
			int row = (int)decoder.GetInt();
			int col = (int)decoder.GetInt();
			if (row <= 0 || col <= 0)
				return -1;

			Reset();
			m_row = row;

			int ndict = 0;
			if (flag & TableFlagHasDict)
			{
				ndict = (int)decoder.GetInt();
				if (ndict > 0)
				{
					// 解析字典数据
					int dictIndex = 0;
					while (decoder.GetPos() < size)
					{
						unsigned char flag = (unsigned char)decoder.GetInt(0);
						kEncodeType type = (kEncodeType)(flag&EncodeTypeMask);
						FieldCollectorPtr collector = new FieldCollector(type, dictIndex, row);

						BASSERT(flag&FieldFlagHasDictIndex);
						int ncount = (int)decoder.GetInt();
						VarValue fieldValue(0);
						for (int i = 0; i < row; i++)
						{
							decoder.GetValue(type, fieldValue, this);
							collector->AddValue(i, fieldValue);
						}
						m_dicts.push_back(collector);
					}
				}
			}


			std::vector<FieldKey> names;
			if (flag & TableFlagHasFieldNames)
			{
				names.reserve(col);
				unsigned char nameflag = (int)decoder.GetInt();
				kEncodeType type = (kEncodeType)(nameflag&EncodeTypeMask);
				kNameType nametype = (kNameType)(nameflag >> TypeBitCount);
				if (type == kEncodeTypeVarInt && nametype == kNameTypeIntIncrement)
				{
					int firstkey = (int)decoder.GetInt();
					for (int i = 0; i < col; i++)
					{
						names.push_back(FieldKey(firstkey + i));
					}
				}
				else if (type == kEncodeTypeVarInt && nametype == kNameTypeIntMultiIncrement)
				{
					int narray = (int)decoder.GetInt(), ntotal = 0;
					std::vector<IncArray> arrays; arrays.reserve(narray);
					for (int i = 0; i < narray;i++)
					{
						int base = (int)decoder.GetInt();
						int delta = (int)decoder.GetInt();
						int count = (int)decoder.GetInt();
						ntotal += count;
						for (int k = 0; k < count;k++)
							names.push_back(FieldKey(base+delta*k));

					}
					BASSERT(ntotal == col);
				}
				else
				{
					for (int i = 0; i < col; i++)
					{
						VarValue colname;
						if (!decoder.GetValue(type, colname, this))
							return -1;
						if (colname.type == kExpectTypeInt)
							names.push_back(FieldKey((int)colname.i));
						else if (colname.type == kExpectTypeString)
							names.push_back(FieldKey(colname.str.ptr, colname.str.len));
						else
							return -1;
					}
				}

				BASSERT(names.size() == col);
			}

			int colIndex = 0;
			while (decoder.GetPos()<size)
			{
				// type,opbitmap?,dictid?,bitwidth?,v0,v1,v2,v3,...
				FieldCollectorPtr collector=DecodeColumn(decoder, row, colIndex);
				if (!collector)
					return -1;
				if (colIndex < (int)names.size())
					collector->SetKey(names[colIndex]);
				m_collectors.push_back(collector);
				colIndex++;
			}

			BASSERT(m_collectors.size() == col);
			// 将CollectorArray按照名称排序,便于外部按照名称来获取字段
			if (m_collectors.size()>1)
				std::sort(m_collectors.begin(), m_collectors.end(), CollectorSortByKey());
			return decoder.GetPos();
		}
	}//namespace base;
}//namespace ss;
